#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
历史数据服务
专门用于获取股票的历史数据，包括昨日成交量等关键指标
"""

import requests
import logging
from datetime import datetime, timedelta, date
from typing import Dict, Optional, List


class HistoricalDataService:
    """历史数据服务类"""

    def __init__(self):
        self.logger = logging.getLogger(__name__)

        # 东方财富K线数据接口配置
        self.eastmoney_kline_url = (
            "http://push2his.eastmoney.com/api/qt/stock/kline/get"
        )
        self.eastmoney_params = {
            "ut": "bd1d9ddb04089700cf9c27f6f7426281",
            "fields1": "f1,f2,f3,f4,f5,f6",
            "fields2": "f51,f52,f53,f54,f55,f56,f57,f58,f59,f60,f61",
            "klt": 101,  # 日K线
            "fqt": 1,  # 前复权
            "end": "20500101",
            "lmt": 10,  # 获取最近10天数据
        }

    def get_previous_day_volume(
        self, stock_code: str, target_date: date = None
    ) -> Optional[int]:
        """
        获取指定股票的前一交易日成交量

        Args:
            stock_code: 股票代码（如 '000001'）
            target_date: 目标日期，默认为昨天

        Returns:
            前一交易日成交量（手），获取失败返回None
        """
        if target_date is None:
            target_date = date.today() - timedelta(days=1)

        # 使用东方财富K线接口
        volume = self._get_volume_from_eastmoney_kline(stock_code, target_date)
        if volume is not None:
            return volume

        self.logger.warning(f"无法获取股票 {stock_code} 在 {target_date} 的成交量数据")
        return None

    def get_batch_previous_day_volumes(
        self, stock_codes: List[str], target_date: date = None
    ) -> Dict[str, Optional[int]]:
        """
        批量获取多只股票的前一交易日成交量（优化版：一次API调用获取所有股票）

        Args:
            stock_codes: 股票代码列表
            target_date: 目标日期，默认为昨天

        Returns:
            股票代码到成交量的映射字典
        """
        if not stock_codes:
            return {}

        if target_date is None:
            target_date = date.today() - timedelta(days=1)

        # 优先尝试批量获取
        batch_result = self._get_batch_volumes_from_eastmoney_kline(
            stock_codes, target_date
        )

        # 如果批量获取失败或数据不完整，对缺失的股票进行单独查询
        missing_codes = [
            code
            for code in stock_codes
            if code not in batch_result or batch_result[code] is None
        ]

        if missing_codes:
            self.logger.debug(
                f"批量获取后仍有 {len(missing_codes)} 只股票缺失数据，进行单独查询"
            )
            for code in missing_codes:
                try:
                    volume = self.get_previous_day_volume(code, target_date)
                    batch_result[code] = volume
                except Exception as e:
                    self.logger.error(f"获取股票 {code} 历史成交量失败: {e}")
                    batch_result[code] = None

        return batch_result

    def _get_batch_volumes_from_eastmoney_kline(
        self, stock_codes: List[str], target_date: date
    ) -> Dict[str, Optional[int]]:
        """批量获取历史成交量（K线API不支持批量，使用单个查询）"""
        result = {}
        
        if not stock_codes:
            return result
        
        self.logger.info(f"开始批量获取 {len(stock_codes)} 只股票的历史成交量...")
        
        # 由于K线API不支持批量历史数据查询，直接使用单个查询
        success_count = 0
        for i, code in enumerate(stock_codes, 1):
            try:
                volume = self._get_volume_from_eastmoney_kline(code, target_date)
                result[code] = volume
                if volume is not None:
                    success_count += 1
                    self.logger.debug(f"进度 {i}/{len(stock_codes)}: {code} 成交量 {volume}")
                else:
                    self.logger.debug(f"进度 {i}/{len(stock_codes)}: {code} 无数据")
            except Exception as e:
                self.logger.error(f"获取 {code} 历史成交量异常: {e}")
                result[code] = None
        
        self.logger.info(f"批量获取历史成交量完成: {success_count}/{len(stock_codes)} 只股票成功")
        return result
    
    def _parse_batch_response(self, data: dict, batch_codes: List[str], target_date: date, batch_index: int) -> Dict[str, Optional[int]]:
        """解析批量API响应"""
        batch_result = {}
        
        try:
            if data and "data" in data and data["data"] is not None:
                # 处理多只股票的数据
                if isinstance(data["data"], list):
                    # 多只股票返回列表
                    for stock_data in data["data"]:
                        if (
                            stock_data
                            and isinstance(stock_data, dict)
                            and "code" in stock_data
                            and "klines" in stock_data
                        ):
                            code = stock_data["code"]
                            klines = stock_data["klines"]
                            if klines and len(klines) > 0:
                                # 取第一条K线数据（因为只查询一天）
                                kline = klines[0]
                                fields = kline.split(",")
                                if len(fields) >= 6:  # 确保有足够的字段
                                    try:
                                        volume = int(float(fields[5]))  # fields[5] = f56 = 成交量
                                        batch_result[code] = volume
                                        self.logger.debug(
                                            f"第{batch_index}批获取 {code} 在 {target_date} 的成交量: {volume}"
                                        )
                                    except (ValueError, TypeError):
                                        batch_result[code] = None
                elif (
                    isinstance(data["data"], dict)
                    and "code" in data["data"]
                    and "klines" in data["data"]
                ):
                    # 单只股票返回对象
                    stock_data = data["data"]
                    code = stock_data["code"]
                    klines = stock_data["klines"]
                    if klines and len(klines) > 0:
                        kline = klines[0]
                        fields = kline.split(",")
                        if len(fields) >= 6:  # 确保有足够的字段
                            try:
                                volume = int(float(fields[5]))  # fields[5] = f56 = 成交量
                                batch_result[code] = volume
                                self.logger.debug(
                                    f"第{batch_index}批获取 {code} 在 {target_date} 的成交量: {volume}"
                                )
                            except (ValueError, TypeError):
                                batch_result[code] = None
                                
            # 对于没有返回数据的股票，标记为None
            for code in batch_codes:
                if code not in batch_result:
                    batch_result[code] = None
                    
            self.logger.debug(f"第{batch_index}批处理完成: {sum(1 for v in batch_result.values() if v is not None)}/{len(batch_codes)} 只股票成功")
            return batch_result

        except Exception as e:
            self.logger.error(f"第{batch_index}批响应解析失败: {e}")
            # 返回空结果，让调用方处理
            return {code: None for code in batch_codes}
    
    def _parse_realtime_response(self, data: dict, batch_codes: List[str], batch_index: int) -> Dict[str, Optional[int]]:
        """解析实时API响应获取成交量数据"""
        batch_result = {}
        
        try:
            if data and "data" in data and data["data"] and "diff" in data["data"]:
                # 实时API返回格式：data.diff是股票列表
                stocks_data = data["data"]["diff"]
                
                for stock_info in stocks_data:
                    if stock_info and isinstance(stock_info, dict):
                        # f12是股票代码，f6是成交量（成交额）
                        code = stock_info.get("f12")  # 股票代码
                        volume_value = stock_info.get("f5")  # f5是成交量（手）
                        
                        if code and volume_value is not None:
                            try:
                                # 实时API的f5字段就是成交量（手）
                                volume = int(volume_value) if volume_value > 0 else 0
                                batch_result[code] = volume
                                self.logger.debug(f"第{batch_index}批实时API获取 {code} 成交量: {volume}")
                            except (ValueError, TypeError):
                                batch_result[code] = None
                                self.logger.debug(f"第{batch_index}批 {code} 成交量解析失败: {volume_value}")
                        else:
                            if code:
                                batch_result[code] = None
                                
            # 对于没有返回数据的股票，标记为None
            for code in batch_codes:
                if code not in batch_result:
                    batch_result[code] = None
                    self.logger.debug(f"第{batch_index}批 {code} 未找到数据")
                    
            success_count = sum(1 for v in batch_result.values() if v is not None)
            self.logger.debug(f"第{batch_index}批实时API处理完成: {success_count}/{len(batch_codes)} 只股票成功")
            return batch_result

        except Exception as e:
            self.logger.error(f"第{batch_index}批实时API响应解析失败: {e}")
            return {code: None for code in batch_codes}

    def _get_volume_from_eastmoney_kline(
        self, stock_code: str, target_date: date
    ) -> Optional[int]:
        """从东方财富K线接口获取单个股票成交量数据"""
        try:
            # 构建API请求参数
            secid = f"1.{stock_code}" if stock_code.startswith('6') else f"0.{stock_code}"
            
            params = self.eastmoney_params.copy()
            params.update({
                "secid": secid,
                "beg": target_date.strftime("%Y%m%d"),
                "end": target_date.strftime("%Y%m%d")
            })
            
            headers = {
                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
                'Referer': 'http://quote.eastmoney.com/',
                'Accept': 'application/json, text/plain, */*'
            }
            
            response = requests.get(self.eastmoney_kline_url, params=params, headers=headers, timeout=10)
            
            if response.status_code == 200:
                data = response.json()
                return self._parse_single_kline_response(data, stock_code, target_date)
            else:
                self.logger.warning(f"获取 {stock_code} 历史K线数据失败: HTTP {response.status_code}")
                return None
                
        except Exception as e:
            self.logger.error(f"获取 {stock_code} 历史成交量异常: {e}")
            return None

    def _process_batch_kline_request(self, batch_codes: List[str], target_date: date, batch_index: int) -> Dict[str, Optional[int]]:
        """处理一批股票的K线数据请求"""
        try:
            # 构建批量API请求参数
            secids = []
            for code in batch_codes:
                if code.startswith('6'):
                    secids.append(f"1.{code}")
                else:
                    secids.append(f"0.{code}")
            
            params = {
                "secids": ",".join(secids),
                "ut": "bd1d9ddb04089700cf9c27f6f7426281",
                "fields1": "f1,f2,f3,f4,f5,f6",
                "fields2": "f51,f56",  # f51=日期, f56=成交量
                "klt": 101,  # 日K线
                "fqt": 1,   # 前复权
                "beg": target_date.strftime("%Y%m%d"),
                "end": target_date.strftime("%Y%m%d")
            }
            
            headers = {
                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
                'Referer': 'http://quote.eastmoney.com/',
                'Accept': 'application/json, text/plain, */*'
            }
            
            response = requests.get(self.eastmoney_kline_url, params=params, headers=headers, timeout=15)
            
            if response.status_code == 200:
                data = response.json()
                return self._parse_batch_response(data, batch_codes, target_date, batch_index)
            else:
                self.logger.error(f"第{batch_index}批K线请求失败: HTTP {response.status_code}")
                return {code: None for code in batch_codes}
                
        except Exception as e:
            self.logger.error(f"第{batch_index}批K线请求异常: {e}")
            return {code: None for code in batch_codes}
    
    def _parse_single_kline_response(self, data: dict, stock_code: str, target_date: date) -> Optional[int]:
        """解析单个股票K线API响应"""
        try:
            if data and "data" in data and data["data"] and "klines" in data["data"]:
                klines = data["data"]["klines"]
                if klines and len(klines) > 0:
                    # 取第一条K线数据（因为只查询一天）
                    kline = klines[0]
                    fields = kline.split(",")
                    if len(fields) >= 6:  # 确保有足够的字段
                        try:
                            volume = int(float(fields[5]))  # fields[5] = f56 = 成交量
                            self.logger.debug(f"获取 {stock_code} 在 {target_date} 的成交量: {volume}")
                            return volume
                        except (ValueError, TypeError):
                            return None
            return None
        except Exception as e:
            self.logger.error(f"解析 {stock_code} K线响应失败: {e}")
            return None
    
    def validate_data_source(self) -> Dict[str, bool]:
        """验证数据源的可用性"""
        results = {}

        # 测试东方财富K线接口
        try:
            test_volume = self._get_volume_from_eastmoney_kline(
                "000001", date.today() - timedelta(days=1)
            )
            results["eastmoney_kline"] = test_volume is not None
        except Exception:
            results["eastmoney_kline"] = False

        return results
